// Common code for displaying errors to the user in various dialogs
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
function formatSyntaxErrorLocation(error) {
const {fileName = '<unknown>', lineNumber = 0, columnNumber = 0} = error;
return `(could not display error: ${e})`;
}
}
+
+/**
+ * Logs a stack trace for `error` with an optional prefix, unless the error
+ * matches `Gio.IOErrorEnum.CANCELLED`.
+ *
+ * @param {Error} error - the error to log
+ * @param {string?} prefix - optional prefix for the message
+ *
+ * @returns {boolean} whether the error was logged
+ */
+export function logErrorUnlessCancelled(error, prefix) {
+ if (error instanceof GLib.Error && Gio.DBusError.is_remote_error(error)) {
+ const errorName = Gio.DBusError.get_remote_error(error);
+ Gio.DBusError.strip_remote_error(error);
+ error = Gio.DBusError.new_for_dbus_error(errorName, error.message);
+ }
+
+ if (error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
+ return false;
+
+ logError(error, prefix);
+ return true;
+}
--- /dev/null
+import GLib from 'gi://GLib';
+import Gio from 'gi://Gio';
+
+import {logErrorUnlessCancelled} from 'resource:///org/gnome/shell/misc/errorUtils.js';
+
+describe('logErrorUnlessCancelled()', () => {
+ let spy;
+
+ beforeEach(() => {
+ spy = spyOn(globalThis, 'logError');
+ });
+
+ it('logs regular errors', () => {
+ const e = new Error('Test error');
+ expect(logErrorUnlessCancelled(e)).toBeTrue();
+ expect(spy).toHaveBeenCalled();
+ });
+
+ it('logs GErrors', () => {
+ const e = GLib.Error.new_literal(
+ Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED, 'Failed');
+ expect(logErrorUnlessCancelled(e)).toBeTrue();
+ expect(spy).toHaveBeenCalled();
+ });
+
+ it('does not log CANCELLED errors', () => {
+ const e = GLib.Error.new_literal(
+ Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED, 'Cancelled');
+ expect(logErrorUnlessCancelled(e)).toBeFalse();
+ expect(spy).not.toHaveBeenCalled();
+ });
+
+ it('handles remote errors', () => {
+ function createDBusError(code, message) {
+ const e = GLib.Error.new_literal(
+ Gio.IOErrorEnum, code, message);
+ return Gio.DBusError.new_for_dbus_error(
+ Gio.DBusError.encode_gerror(e), message);
+ };
+
+ let e = createDBusError(Gio.IOErrorEnum.CANCELLED, 'Cancelled');
+ expect(logErrorUnlessCancelled(e)).toBeFalse();
+ expect(spy).not.toHaveBeenCalled();
+
+ e = createDBusError(Gio.IOErrorEnum.FAILED, 'Failed');
+ expect(logErrorUnlessCancelled(e)).toBeTrue();
+ expect(spy).toHaveBeenCalled();
+ });
+});